/**
 * This file is Copyright © 2008 Software Craftsmen Limited. All Rights Reserved.
 */
package com.softwarecraftsmen.orogeny.filing.fileSystems;

import com.softwarecraftsmen.orogeny.filing.Folder;
import org.jetbrains.annotations.NotNull;

import static java.lang.String.format;
import java.util.LinkedHashMap;
import java.util.List;
import static java.util.Locale.UK;
import java.util.Map;
import java.io.File;

//TODO: UNC short and long support
public class WindowsCaseInsensitiveFileSystem extends AbstractFileSystem
{
	private static final Map<String, WindowsCaseInsensitiveFileSystem> cache = new LinkedHashMap<>();

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem A = windowsCaseInsensitiveFileSystem("A:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem B = windowsCaseInsensitiveFileSystem("B:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem C = windowsCaseInsensitiveFileSystem("C:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem D = windowsCaseInsensitiveFileSystem("D:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem E = windowsCaseInsensitiveFileSystem("E:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem F = windowsCaseInsensitiveFileSystem("F:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem G = windowsCaseInsensitiveFileSystem("G:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem H = windowsCaseInsensitiveFileSystem("H:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem I = windowsCaseInsensitiveFileSystem("I:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem J = windowsCaseInsensitiveFileSystem("J:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem K = windowsCaseInsensitiveFileSystem("K:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem L = windowsCaseInsensitiveFileSystem("L:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem M = windowsCaseInsensitiveFileSystem("M:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem N = windowsCaseInsensitiveFileSystem("N:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem O = windowsCaseInsensitiveFileSystem("O:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem P = windowsCaseInsensitiveFileSystem("P:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem Q = windowsCaseInsensitiveFileSystem("Q:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem R = windowsCaseInsensitiveFileSystem("R:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem S = windowsCaseInsensitiveFileSystem("S:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem T = windowsCaseInsensitiveFileSystem("T:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem U = windowsCaseInsensitiveFileSystem("U:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem V = windowsCaseInsensitiveFileSystem("V:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem W = windowsCaseInsensitiveFileSystem("W:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem X = windowsCaseInsensitiveFileSystem("X:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem Y = windowsCaseInsensitiveFileSystem("Y:");

	@NotNull
	public static final WindowsCaseInsensitiveFileSystem Z = windowsCaseInsensitiveFileSystem("Z:");

	private WindowsCaseInsensitiveFileSystem(final @NotNull String rootFolderName)
	{
		super("\\", ";", rootFolderName);
	}

	@NotNull
	public static WindowsCaseInsensitiveFileSystem windowsCaseInsensitiveFileSystem(final @NotNull String rootFolderName)
	{
		if (rootFolderName.length() == 0)
		{
			throw new IllegalArgumentException("Empty rootFolderName is unsupported");
		}
		final String normalisedLengthRootFolderName;
		if (rootFolderName.length() == 1)
		{
			normalisedLengthRootFolderName = rootFolderName + ":";
		}
		else if (rootFolderName.length() == 3)
		{
			if (!rootFolderName.endsWith("\\"))
			{
				throw new IllegalArgumentException(format(UK, "UNC etc root folder names are unsupported (%1$s)", rootFolderName));
			}
			normalisedLengthRootFolderName = rootFolderName.substring(0, 2);
		}
		else if (rootFolderName.length() == 2)
		{
			normalisedLengthRootFolderName = rootFolderName;
		}
		else
		{
			throw new IllegalArgumentException(format(UK, "UNC etc root folder names are unsupported (%1$s)", rootFolderName));
		}
		final String casedRootFolderName = normalisedLengthRootFolderName.toUpperCase(UK);
		if (casedRootFolderName.charAt(1) != ':' || "ABCDEFGHIJKLMNOPQRSTUVWXYZ".indexOf(casedRootFolderName.charAt(0)) == -1)
		{
			throw new IllegalArgumentException(format(UK, "UNC etc root folder names are unsupported (%1$s)", rootFolderName));
		}
		if (containsKey(casedRootFolderName))
		{
			return get(casedRootFolderName);
		}
		final WindowsCaseInsensitiveFileSystem fileSystem = new WindowsCaseInsensitiveFileSystem(casedRootFolderName);
		cache.put(casedRootFolderName, fileSystem);
		return fileSystem;
	}

	@Override
	protected boolean isAbsolute(final @NotNull String firstFolderDescription)
	{
		return containsKey(firstFolderDescription);
	}

	public boolean isHidden(final @NotNull List<? extends Folder> folders)
	{
		if (super.isHidden(folders))
		{
			return true;
		}
		final String filePath = toFileSystemSpecificPath(folders);
		return new File(filePath).isHidden();
	}

	public boolean isHidden(final @NotNull List<? extends Folder> folders, final @NotNull String fileName)
	{
		return super.isHidden(folders, fileName) || fileName.startsWith(".");
	}

	@NotNull
	@Override
	protected FileSystem actualFileSystem(final @NotNull String firstFolderDescription)
	{
		return get(firstFolderDescription);
	}

	private static WindowsCaseInsensitiveFileSystem get(final String rootName) {return cache.get(rootName);}

	private static boolean containsKey(final String rootName) {return cache.containsKey(rootName);}
}
